home *** CD-ROM | disk | FTP | other *** search
/ Mac Mania 2 / MacMania 2.toast / Demo's / Tools&Utilities / Programming / MPS disk 1.0.1 / Chapter 09 / ZoomKey / ZoomKey.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-19  |  5.3 KB  |  147 lines  |  [TEXT/KAHL]

  1. #include <Traps.h>
  2. #include <SetupA4.h>
  3.  
  4. /*******************************************************************************
  5.  
  6.     Function prototypes.
  7.  
  8. *******************************************************************************/
  9.  
  10. void        main();
  11. pascal long    MyMenuKey(short ch);
  12.  
  13. typedef pascal long (*MenuKeyProc)(short ch);
  14. MenuKeyProc    oldMenuKeyAddress;
  15.  
  16. /*******************************************************************************
  17.  
  18.     main
  19.  
  20.     When INITs are loaded, the operating system jumps to the first byte in the
  21.     resource to execute them. Under THINK C, the compiler adds a little
  22.     snippet of code at the beginning of the INIT that jumps to main(), which
  23.     means that main() can appear anywhere in the source. Under MPW, this isn’t
  24.     done for you, so you have to make sure that main() is the first procedure
  25.     in your source code. 
  26.  
  27.     In order for INITs to stay resident, they must be loaded into the System
  28.     heap. Because they contain executable instructions that can be called at
  29.     any time, the INIT resource should be locked. Since they’ll remain locked
  30.     during the entire time the computer is on, they should be loaded as low in
  31.     the heap as possible to prevent fragmentation. Setting the resSysHeap and
  32.     resLocked bits of our INIT resource will do this for us. However, none of
  33.     this prevents our INIT resource from being removed from memory as soon as
  34.     the file it’s in is closed. Therefore, the first thing our main() routine
  35.     does detach the INIT from the resource file. 
  36.  
  37.     Next, we plug ourselves into the MenuKey() routine. This is done in two
  38.     steps. First, we get the address of the current MenuKey() routine and save
  39.     it. Then we install the address of our own custom routine. 
  40.  
  41. *******************************************************************************/
  42. void    main()
  43. {
  44.     Ptr    ourAddress;
  45.  
  46.     RememberA0();
  47.     SetUpA4();
  48.  
  49.     asm {
  50.         move.l    A0, ourAddress        ; A0 points to the beginning of the
  51.                                     ; INIT, courtesy of the THINK glue
  52.         }
  53.     DetachResource(RecoverHandle(ourAddress));
  54.  
  55.     oldMenuKeyAddress = (MenuKeyProc) GetToolTrapAddress(_MenuKey);
  56.     SetToolTrapAddress((long) MyMenuKey, _MenuKey);
  57.     RestoreA4();
  58. }
  59.  
  60. /*******************************************************************************
  61.  
  62.     MyMenuKey
  63.  
  64.     This the patch that gets called whenever any application calls MenuKey.
  65.     What we want to do here is detect whenever the user presses Command-Space.
  66.     When they do, we zoom the frontmost window. 
  67.  
  68.     Under the THINK environments, you are allowed to have global variables in
  69.     standalone code as long as you call SetUpA4() first. Since we’ve stored
  70.     the address of the original MenuKey routine in a global, the first we do
  71.     is call SetUpA4(). Then we call the original MenuKey so that it can do its
  72.     processing. 
  73.  
  74.     Next, it’s time for our custom code to step in. When MenuKey returns, we
  75.     check for 3 conditions: 1) that the user pressed Command-Space, 2) that
  76.     Command-Space doesn’t correspond to anything in the current application’s
  77.     menus, and 3) that there is a front window. If we pass this battery of
  78.     tests, we much check to see if that front window can be zoomed.
  79.     Unfortunately, there isn’t really a good way of doing this. While you can
  80.     get zoomable windows by specifying a wDefProcID of 8 or 12, this is just a
  81.     convention for the standard system WDEF. There’s no guarantee that WDEFs
  82.     written by Worldwide Washington WindowsWare will use the same convention.
  83.     Also, checking the window to see if its procID is 8 or 12 will fail if
  84.     Apple defines proc IDs 9-11 to produce zoomable windows as well. On the
  85.     other hand, they could equally as well define proc IDs 9-11 to produce
  86.     non-zoomable windows as well. Another solution is needed. 
  87.  
  88.     The one we’ve chosen here is to call FindWindow on the location where we
  89.     expect the zoom box to be. Obviously, this will fail if the WDEF
  90.     programmer puts the zoom box in a different place, but it should at least
  91.     work for all of Apple’s WDEF designs. 
  92.  
  93.     If FindWindow returns inZoomIn or inZoomOut, we know that the window has a
  94.     zoom box. All that remains to do is to zoom the window. Initially, you
  95.     might think that a simple call to ZoomWindow will do the trick.
  96.     Unfortunately, this is not so. Zooming a window involves more than just
  97.     calling ZoomWindow. For instance, if there are any scroll bars in the
  98.     window, they must be moved. No, a better solution is to fake a mouse click
  99.     on the same spot that we used to test for a zoombox. 
  100.  
  101. *******************************************************************************/
  102. pascal long MyMenuKey(short ch)
  103. {
  104.     long        result;
  105.     WindowPtr    theWindow;
  106.     Rect        *rectPtr;
  107.     Point        location;
  108.     short        part;
  109.     EvQElPtr    qElPtr;
  110.  
  111.     SetUpA4();
  112.  
  113.     result = oldMenuKeyAddress(ch);
  114.  
  115.     if ( ((char) ch == ' ')                            // If Command-Space ...
  116.       && (result == 0)                                // ... and not in menus ...
  117.       && ((theWindow = FrontWindow()) != nil)) {    // ... and has front window ...
  118.  
  119.          rectPtr = &((**(((WindowPeek)theWindow)->strucRgn)).rgnBBox);
  120.          location.h = rectPtr->right - 15;
  121.          location.v = rectPtr->top + 10;
  122.  
  123.         part = FindWindow(location, &theWindow);
  124.  
  125.         if ((part == inZoomIn) || (part == inZoomOut)) {    // ... and it zooms.
  126.  
  127.              /*
  128.                  === Bad way ===
  129.  
  130.                  GetPort(&oldPort);
  131.                  SetPort(theWindow);
  132.                  ZoomWindow(theWindow, part, TRUE);
  133.                  SetPort(oldPort);
  134.              */
  135.  
  136.             PPostEvent(mouseDown, 0, &qElPtr);
  137.             qElPtr->evtQWhere = location;
  138.             PPostEvent(mouseUp, 0, &qElPtr);
  139.             qElPtr->evtQWhere = location;
  140.         }
  141.     }
  142.  
  143.     RestoreA4();
  144.  
  145.     return result;
  146. }
  147.